
package com.yishe.intercepter;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.ImmutableMap;
import com.yishe.api.RestCodeConstants;
import com.yishe.config.ObjectRestResponse;
import com.yishe.context.BaseContextHandler;
import com.yishe.entites.mysql.YsStaff;
import com.yishe.exception.UserTokenException;
import com.yishe.redis.RedisUtils;
import com.yishe.utils.CommonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * create by: chusifeng
 * Create in 2021/4/9 9:49
 * Description:登录权限相关拦截器
 * <p>Example</p>
 */
@Configuration
@Slf4j
public class UserAuthInterceptor extends HandlerInterceptorAdapter {
	/** 是否启用登录校验，暂时作废处理 **/
	@Value(value = "${auth.user.enabled:true}")
	private boolean enabled;

	/** 请求头token存储属性 **/
	@Value(value = "${auth.user.token-header:Authorization}")
	private String tokenHeader;

	/** 登录失效时间(秒)【默认2个小时】 **/
	@Value(value = "${yishe.user.token.expireTime:1800}")
	private int tokenExpireTime;

	public UserAuthInterceptor() {
		// TODO Auto-generated constructor stub
		log.info("用户拦截器参数初始化  enabled:{}", enabled);
		log.info("用户拦截器参数初始化  tokenHeader:{}", tokenHeader);
		log.info("用户拦截器参数初始化  tokenExpireTime:{}", tokenExpireTime);
	}

	/**
	 * 预处理回调方法，实现处理器的预处理（如检查登陆），第三个参数为响应的处理器，自定义Controller
	 * 返回值：true表示继续流程（如调用下一个拦截器或处理器）；false表示流程中断（如登录检查失败），
	 * 不会继续调用其他的拦截器或处理器，此时我们需要通过response来产生响应；
	 *
	 * @param request
	 * @param response
	 * @param handler
	 * @return boolean
	 * @author zdh
	 * @modifyTime 2019/11/21 9:58:00
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		try {
			String requestUrl = request.getRequestURI();
			String token = request.getHeader(this.tokenHeader);
			log.info("用户拦截器  start,请求地址：{}", requestUrl);
			if (CommonUtils.isRead(request)) {
				log.info("拦截器请求 body json 参数为：{}", CommonUtils.getBodyString(request));
			}
			/** 1. 用户信息存储及拦截token认证 ***/
			this.doUserParam(token);


		} catch (UserTokenException e) {
			log.error("拦截器异常:{}", e);
			ObjectRestResponse res = new ObjectRestResponse();
			res.setResultCode(RestCodeConstants.EX_USER_INVALID_CODE);
			res.setResultMsg(e.toString());
			//获取flag标志返回到页面
			String flag =request.getParameter("flag");
			if (StringUtils.isNotBlank(flag)) {
				res.setData(ImmutableMap.of("flag", request.getParameter("flag")));
			}
			returnJson(response, res);
			return false;
		}

		return super.preHandle(request, response, handler);
	}

	/**
	 * 用户信息存储
	 *
	 * @param token
	 * @author zdh
	 * @modifyTime 2019/11/21 11:20:00
	 */
	private void doUserParam(String token) throws UserTokenException {

		RedisUtils instance = RedisUtils.getInstance();
		/**
		 * 1. redis通过token查用户信息
		 */
		String userInfoJson = (String) instance.get(RestCodeConstants.CommonConstants.REGION_LGOIN, token);
		if (StringUtils.isBlank(userInfoJson) || StringUtils.isEmpty(userInfoJson)) {
			throw new UserTokenException("登录已失效,请重新登录后重试!");
		}
		// 根据用户token存储用户信息
		instance.set(RestCodeConstants.CommonConstants.REGION_LGOIN, token, userInfoJson, tokenExpireTime);

		// 用户信息
		YsStaff userKeyInfo = JSONObject.parseObject(userInfoJson, YsStaff.class);
		// 主键id
		int id = userKeyInfo.getId();
		// 登录账号
		String account = userKeyInfo.getAccount();
		// 中文姓名
		String chinesename = userKeyInfo.getName();

		// 根据用户code存储用户信息
		instance.set(RestCodeConstants.CommonConstants.REGION_LGOIN, account, userKeyInfo, tokenExpireTime);

		/**
		 * 2. 用户信息存入上下文中
		 */
		BaseContextHandler.setUserID(id);// 用户表主键id
		BaseContextHandler.setUserCode(account);// 用户编码（登录名）
		BaseContextHandler.setUserName(chinesename);// 用户中文名称
		BaseContextHandler.setToken(token);// 登录的token信息
		BaseContextHandler.set(RestCodeConstants.CommonConstants.BASE_USER, userKeyInfo);// 用户信息

	}

	/**
	 * 整个请求处理完毕回调方法，即在视图渲染完毕时回调，如性能监控中我们可以在此记录结束时间并输出消耗时间，
	 * 还可以进行一些资源清理，类似于try-catch-finally中的finally，但仅调用处理器执行链中
	 *
	 * @param request
	 * @param response
	 * @param handler
	 */
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		BaseContextHandler.remove();
		log.debug(" BaseContextHandler Param is remove.");
		super.afterCompletion(request, response, handler, ex);
	}

	/**
	 * 响应内容
	 *
	 * @param response
	 * @param o
	 * @modifyTime 2019/11/22 12:23:00
	 */
	private void returnJson(HttpServletResponse response, Object o) {
		PrintWriter writer = null;
		response.setCharacterEncoding("UTF-8");
		response.setContentType("application/json; charset=utf-8");
		try {
			writer = response.getWriter();
			writer.print(JSONObject.toJSONString(o));
		} catch (IOException e) {
			log.error("response error", e);
		} finally {
			if (writer != null) {
				writer.close();
			}
		}
	}
}
